package com.xsomnus.java_basic.cacheline;

import java.util.concurrent.CountDownLatch;

/**
 * @author 叶小夏
 * @since 2019-08-20 15:13
 */
public class FalseSharing implements Runnable {
    //线程个数
    public static int NUM_THREADS = 4; // change
    //循环修改数组中数据的次数
    public final static long ITERATIONS = 500L * 1000L * 1000L;
    //数组下标
    private final int arrayIndex;
    //操作的数组
    private static VolatileLong[] longs;

    private static final CountDownLatch cdl = new CountDownLatch(NUM_THREADS);

    public FalseSharing(final int arrayIndex) {
        this.arrayIndex = arrayIndex;
    }

    public static void main(final String[] args) throws Exception {
        Thread.sleep(10000);
        System.out.println("starting....");
        //初始化数组
        longs = new VolatileLong[NUM_THREADS];
        for (int i = 0; i < longs.length; i++) {
            longs[i] = new VolatileLong();
        }
        final long start = System.nanoTime();
        runTest();
        System.out.println("duration = " + (System.nanoTime() - start));
    }

    private static void runTest() throws InterruptedException {
        //初始化线程组
        Thread[] threads = new Thread[NUM_THREADS];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new FalseSharing(i));
        }
        //开始运行所有线程
        for (Thread t : threads) {
            t.start();
        }
        //主线程阻塞直到所有子线程结束
        cdl.await();
    }

    @Override
    public void run() {
        //多线程情况下持续修改数组中某一个volatile值
        long i = ITERATIONS + 1;
        while (0 != --i) {
            longs[arrayIndex].value = i;
        }
        cdl.countDown();
    }
}

/**
 * 数组保存了VolatileLongPadding，其中数组中一个long类型保存数组长度，算上
 * 自身long类型value，需要再填充6个long类型，就能将数组中的对象填充满一个 缓存行。
 * 注意：这里使用继承的方式实现缓存行对齐，因为Java7编译器会优化无效的字段。
 */
class VolatileLongPadding {
    // 如果不需要填充，只需要注释掉这段代码即可
   public volatile long p1, p2, p3, p4, p5, p6;
}

class VolatileLong extends VolatileLongPadding {
    //实际操作的值
    public volatile long value = 0L;
}